<script lang="ts" setup>
import { uploadAudioService } from '../api/voice'
import { ref } from 'vue'

interface Meaasge {
  type: 'text' | 'audio'
  content: string
}
const messages = ref<Meaasge[]>([]) //存储聊天信息
const isRecording = ref(false) // 是否正在录音
const mediaRecorder = ref<MediaRecorder | null>(null) // 媒体录音器
const audioChunks = ref<Blob[]>([]) // 存储音频数据

// 开始录音
const startRecording = async () => {
  // 清空之前的数据
  audioChunks.value = []
  // navigator.mediaDevices.getUserMedia()：主要用于访问和控制用户的媒体设备(如麦克风、摄像头),返回promise
  //可选参数：constraints(约束对象)=>
  // 1.audio: true =>audio: {}：可以传递一个对象来更精确地控制音频的配置
  // 2.video: true：=>video: {}
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
  // MediaRecorder 是一个用于录制 MediaStream（例如音频或视频流）并将其保存为可下载的媒体文件
  //参数 stream(必选)：包含音频和/或视频轨道的MediaStream对象， options(可选)：
  // MediaRecorder 的主要方法：start():开始录制 stop():停止录制 pause():暂停录制 resume():恢复录制
  //  MediaRecorder 的主要事件：ondataavailable：录制的数据可用时触发,会传递一个 BlobEvent 对象，其中包含录制的媒体数据
  //  onstart：开始时触发 onstop：停止时触发 onerror：发生错误时触发
  mediaRecorder.value = new MediaRecorder(stream)
  // 录制数据可用时的操作
  mediaRecorder.value.ondataavailable = (event: BlobEvent) => {
    // 存储音频数据
    audioChunks.value.push(event.data)
  }

  // 录制停止时的操作
  mediaRecorder.value.onstop = handleRecordingStop
  mediaRecorder.value.start()
  isRecording.value = true
}

// 停止录音
const stopRecording = () => {
  mediaRecorder.value?.stop()
  isRecording.value = false
}

// 处理录音停止后的操作
const handleRecordingStop = async () => {
  // 创建了一个新的 Blob 对象，Blob 是一种表示二进制数据的对象
  // audioChunks：存储的音频数组，当重新录制时就清空了
  const audioBlob = new Blob(audioChunks.value, { type: 'audio/wav' })
  // 用于根据 Blob 对象创建一个临时的 URL，该 URL 可以指向 Blob 中的二进制数据
  const audioUrl = URL.createObjectURL(audioBlob)
  // 存储音频信息：当不需要时可改
  messages.value.push({ type: 'audio', content: audioUrl })
  console.log('🚀 ~ handleRecordingStop ~ messages.value:', messages.value)
  // 上传音频到后端
  try {
    const res = await uploadAudioService(audioBlob)
    // 假设返回的是转换后的文字,加到聊天信息数组里
    messages.value.push({ type: 'text', content: res.data })
  } catch (error) {
    console.log('上传失败：', error)
  }
}
</script>
<template>
  <div id="app">
    <div class="chat-container">
      <!-- 显示聊天消息 -->
      <div class="messages">
        <div class="message" v-for="(message, index) in messages" :key="index">
          <!-- 转文字信息 -->
          <div v-if="message.type === 'text'" class="message-text">{{ message.content }}</div>
          <!-- 原本语音信息 -->
          <div v-if="message.type === 'audio'" class="message-auto">
            <audio :src="message.content" controls></audio>
          </div>
        </div>
      </div>
      <!-- 语音录制按钮 -->
      <div class="controls">
        <el-button
          :type="isRecording ? 'info' : 'primary'"
          plain
          @click="startRecording"
          :disabled="isRecording"
          >开始录音</el-button
        >
        <el-button
          :type="!isRecording ? 'info' : 'primary'"
          plain
          @click="stopRecording"
          :disabled="!isRecording"
          >停止录音</el-button
        >
      </div>
    </div>
  </div>
</template>
<style scoped>
#app {
  text-align: center;
  color: #2c3e50;
}

.chat-container {
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
  background-color: #f9f9f9;
  border-radius: 10px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.messages {
  max-height: 400px;
  overflow-y: auto;
  margin-bottom: 20px;
  padding: 10px;
}

.message {
  margin-bottom: 10px;
}

.message-text {
  background-color: #e0e0e0;
  padding: 10px;
  border-radius: 5px;
  display: inline-block;
}

.message-audio audio {
  max-width: 100%;
  margin-top: 5px;
}

.controls {
  display: flex;
  justify-content: center;
}
</style>
